#ifndef AUTOBAHNPROTOIMPL_H
#define AUTOBAHNPROTOIMPL_H

#include "WAMP.h"
#include "Session.h"
#include "JsonParser.h"
#include "AutobahnApi.h"
#include "Params.h"
#include "STM32FreeRTOS.h"
typedef std::map<int, std::string> PubTable;
class cautobahnproto_impl
{

public:
	cautobahnproto_impl(){};
	~cautobahnproto_impl(){};
	void on_abort(uint8_t *payload, size_t length);
	void on_goodbye(uint8_t *payload, size_t length);
	void on_welcome(uint8_t *payload, size_t length);
	void on_errormsg(uint8_t *payload, size_t length);
	void on_published(uint8_t *payload, size_t length);
	void on_subscribed(uint8_t *payload, size_t length);
	void on_unsubscribed(uint8_t *payload, size_t length);
	void on_event(uint8_t *payload, size_t length);
	void on_result(uint8_t *payload, size_t length);
	void on_registered(uint8_t *payload, size_t length);
	void on_unregistered(uint8_t *payload, size_t length);
	void on_invocation(uint8_t *payload, size_t length);
	void return_call(wamp_param *message);

	void wampstatemachine(uint8_t *payload, size_t length);
	void wampstatemachine(e_message_codes _wampstate, uint8_t *payload, size_t length);
	void send_hello(const char *topic);
	template <typename... Args>
	void publish(const char *topic, Args... values);
	void subscribe(const char *topic, t_wamp_cb cb);
	bool is_connected();
	void unsubscribe(const char *topic);
	bool is_subscribed(const char *topic);
	void rpc_register(const char *topic, t_wamp_cb cb);
	template <typename... Args>
	wamp_param *rpc_call(const char *topic, Args... values)
	{

		rpc_param.reset();
		char *tmp;
		if (sizeof...(values) != 0)
		{
			rpc_param.add(values...);
			tmp = const_cast<char *>(rpc_param.asString());
		}
		else
		{
			tmp = NULL;
		}
		int reqId = generate_request_id();
		// this->add_publish_record(reqId, topic);
		send_towire(_parser.get_rpccall(reqId, topic, tmp));
		uint32_t _last = millis();
		while (_session._rpcresult != true)
		{
			this->loop();
			if ((millis() - _last) > 10000)
			{
				rpc_param.reset();
				break;
			}
			vTaskDelay(1);
		}
		_session._rpcresult = false;
		return &rpc_param;
	}

	wamp_param *rpc_call(const char *topic);
	wamp_param *rpc_call_async(const char *topic, t_cb cb);
	template <typename... Args>
	wamp_param *rpc_call_async(const char *topic, t_cb cb, Args... values)
	{
		rpc_param.reset();
		// int breakout_counter = 0;
		char *tmp;
		if (sizeof...(values) != 0)
		{
			rpc_param.add(values...);
			tmp = const_cast<char *>(rpc_param.asString());
		}
		else
		{
			tmp = NULL;
		}
		int reqId = generate_request_id();

		//this->_session.add_publish_record(reqId, topic);
		send_towire(_parser.get_rpccall(reqId, topic, tmp));
		return 0;
	}

	virtual void notify_welcome() = 0;
	virtual void send_towire(const char *topic) = 0;
	virtual void loop() = 0;

	void setrealm(char *realm) { this->_session.realm = realm; };

	int generate_request_id();

	bool _connected = false;
	csession _session;
	cjsonparser _parser;
	wamp_param pub_param;
	wamp_param sub_param;
	wamp_param rpc_param;

	e_message_codes _wampstate;
	PubTable publish_table;

	bool add_publish_record(int reqId, const char *topic)
	{
		publish_table.insert(std::make_pair(reqId, std::string(topic)));
		return 0;
	}
};

#endif
